package com.healthySys.backend.config.security;

import com.healthySys.backend.config.security.filter.JWTFilter;
import com.healthySys.backend.config.security.handler.CustomLogoutSuccessHandler;
import com.healthySys.common.utils.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;

import java.util.List;

@Slf4j
@Configuration
@EnableMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurityConfig {

    @Resource
    private JWTFilter jwtFilter;
    @Resource
    private CustomLogoutSuccessHandler customLogoutSuccessHandler;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        // ==================== 基础安全配置 ====================
        //CSRF
        http.csrf(AbstractHttpConfigurer::disable); //纯API项目禁用CSRF配置
        //CORS
        http.cors(cors->cors
                .configurationSource(request -> {
                    CorsConfiguration config = new CorsConfiguration();
                    config.setAllowedOrigins(List.of("*")); // 允许所有来源todo: 前端地址
                    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); // 允许的方法
                    config.setAllowedHeaders(List.of("*")); // 允许所有请求头
                    config.setExposedHeaders(List.of("*")); // 暴露所有响应头
                    return config;
                })
        );
        //会话管理
        http.sessionManagement(session->session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)//配置无状态对话,每次请求必须携带JWT
        );

        // ==================== 请求授权配置 ====================
        http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> {
                    authorizationManagerRequestMatcherRegistry
                            .requestMatchers("/sys/login").permitAll() // 允许公开访问的路径
                            //.requestMatchers("/admin/**").hasRole("ADMIN") // 仅允许ADMIN角色访问/admin路径下的资源
                            .requestMatchers("/static/**", "/resources/**").permitAll() // 静态资源路径
                            .anyRequest().authenticated(); // 其他所有请求都需要认证后访问
                }
        );
        http
                .logout(logout -> logout
                        .logoutUrl("/sys/logout") // 自定义登出端点
                        .logoutSuccessHandler(customLogoutSuccessHandler) //登出处理
                        .invalidateHttpSession(true)
                );
        // ==================== 异常处理配置 ====================
        http.exceptionHandling(ex -> ex
                .authenticationEntryPoint((request, response, authException) -> {
                    log.info("用户未登录");
                    ResponseUtils.writeJsonResponse(response, HttpServletResponse.SC_UNAUTHORIZED, 401, "请先登录");
                })
                .accessDeniedHandler((request, response, accessDeniedException) -> {
                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                    String name = authentication.getName();
                    log.info("{},用户权限不足",name);
                    ResponseUtils.writeJsonResponse(response, HttpServletResponse.SC_FORBIDDEN, 403, "权限不足");
                })
        );

        // ==================== 过滤器配置 ====================

        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); // 添加JWT过滤器到过滤器链中


        //==================== 响应头安全加固 ====================
        http.headers(headers -> headers
                .httpStrictTransportSecurity(hsts -> hsts
                        .includeSubDomains(true)
                        .preload(true)
                        .maxAgeInSeconds(31536000) // 强制HTTPS
                )
                .contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'")) // 防XSS
                .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin) // 防点击劫持
        );
        return http.build();

    }

    //身份验证管理器
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
        return authConfig.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance(); //使用无加密编码器 todo 更改密码编辑器
    }





}
